package com.chiang.myscrollview.ui;

import android.R.integer;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.View.MeasureSpec;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;

/**
 * @author Chiang.CMBA
 * @date 创建时间：2015-3-1 上午7:55:51
 * @version v1.0
 * @Description: 自定义View仿ScrollView效果。
 */

public class MyScrollView extends ViewGroup {

	private GestureDetector mDetector;
	private Context mContext; 
	private boolean mIsFling;
	private int mCurrId = 0;
	private float mFirstX;
	private float mFirstY;
	
	private OnPageChangedListener mOnPageChangedListener;
	
//	private MyScroller mScroller;//my 
	private Scroller mScroller;//System
	
	public MyScrollView(Context context) {
		this(context, null);
		// TODO Auto-generated constructor stub
	}
	
	public MyScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.mContext = context;
		mIsFling = false;
		
		initView();
	}

	
	public OnPageChangedListener getOnPageChangedListener() {
		return mOnPageChangedListener;
	}

	public void setOnPageChangedListener(
			OnPageChangedListener mOnPageChangedListener) {
		this.mOnPageChangedListener = mOnPageChangedListener;
	}

	private void initView() {
//		mScroller = new MyScroller(mContext);
		mScroller = new Scroller(mContext);
		
		mDetector = new GestureDetector( mContext , new OnGestureListener() {
			
			@Override
			public boolean onSingleTapUp(MotionEvent e) {
				// TODO Auto-generated method stub
				return false;
			}
			
			@Override
			public void onShowPress(MotionEvent e) {
				// TODO Auto-generated method stub
				
			}
			/**
			 * @param e1 The first down motion event that started the scrolling.
			 * @param e2 The move motion event that triggered the current onScroll.
			 * @param distanceX The distance along the X axis that has been scrolled since the last
			 *              call to onScroll. This is NOT the distance between {@code e1}
			 *              and {@code e2}.
			 * @param distanceY The distance along the Y axis that has been scrolled since the last
			 *              call to onScroll. This is NOT the distance between {@code e1}
			 *              and {@code e2}.
			 * @return true if the event is consumed, else false
			 */
			@Override
			public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
					float distanceY) {
				/**
			     * Move the scrolled position of your view. This will cause a call to
			     * {@link #onScrollChanged(int, int, int, int)} and the view will be
			     * invalidated.
			     * @param x the amount of pixels to scroll by horizontally
			     * @param y the amount of pixels to scroll by vertically
			     * 
			     * 移动当前view内容 移动一段距离
				 * disX	 X方向移的距离		为正是，图片向左移动，为负时，图片向右移动 
				 * disY  Y方向移动的距离
			     */
				scrollBy((int) distanceX, 0);
				
				/**
				 * 将当前视图的基准点移动到某个点  坐标点
				 * x 水平方向X坐标
				 * Y 竖直方向Y坐标
				 *  scrollTo(x,  y);
				 */
				return false;//true if the event is consumed, else false
			}
			
			@Override
			public void onLongPress(MotionEvent e) {
				// TODO Auto-generated method stub
				
			}
			
			/**
			 * When fling, we do the following the jobs:
			 * 1. check the fling direction: velocityX >0? right:left;
			 * 2. scroll to next view: right? (the previous view):(the next view);
			 */
			@Override
			public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
					float velocityY) {
				mIsFling = true;
				if(velocityX > 0 && mCurrId >0){
					mCurrId --;
				}else if(velocityX <0 && mCurrId< getChildCount()-1){
					mCurrId ++;
				}
				scrollToView(mCurrId);
				return false;
			}
			
			@Override
			public boolean onDown(MotionEvent e) {
				// TODO Auto-generated method stub
				return false;
			}
		});
		
	}

	/**
	 * 对子view进行布局，确定子view的位置
	 * changed  若为true ，说明布局发生了变化
	 * l\t\r\b\  是指当前viewgroup 在其父view中的位置 
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		System.out.println("-------onLayout()");
		for(int i=0; i<getChildCount(); i++){
			// TODO How the size of the view is determined?
			View view = getChildAt(i);
			//Specified layout location of the view; the l t r b ,
			//refers to the position in ViewGroup's coordinate system 
			/**
			 * 父view 会根据子view的需求，和自身的情况，来综合确定子view的位置,(确定他的大小)
			 */
			view.layout(i*getWidth(), 0, (i+1)*getWidth(), getHeight());
//			view.getWidth();//得到view真实的大小(mRight - mLeft)；只有在view.layout()方法执行完后，才可以。
		}

	}

	/**
	 * 计算 控件大小，
	 * 做为viewGroup 还有一个责任，，：计算 子view的大小
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		System.out.println("-------onMeasure()");
		// TODO Auto-generated method stub
		//measure the viewgroup's size
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		
		int size = MeasureSpec.getSize(widthMeasureSpec);
		int mode = MeasureSpec.getMode(widthMeasureSpec);
		
		//measure the child view size
		for (int i = 0; i < getChildCount(); i++) {
			View view = getChildAt(i);
			view.measure(widthMeasureSpec, heightMeasureSpec);
			
//			view.getMeasuredWidth() // 得到测量的大小(我们想要的大小),这个大小和实际的大小不一定相等；
		}
	}
	
	/**
	 * 事件传递机制：
	 * 1、执行dispatchTouchEvent()方法，开始分发事件;
	 * 2、执行onInterceptTouchEvent()方法，判断是否中断事件;
	 * 3、执行onTouchEvenet()方法去处理事件;
	 * 
	 */
	
	/**
	 * 分发事件的方法，最早执行。
	 */
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		return super.dispatchTouchEvent(ev);
	}
	
	/**
	 * 是否中断事件的传递
	 * 返回true时，中断事件，执行自己的onTouchEvent方法;
	 * 返回false时，默认处理，不中断，也不执行自己的onTouchEvent方法;
	 */
	@Override
	public boolean onInterceptTouchEvent(MotionEvent event) {
		super.onInterceptTouchEvent(event);
		boolean doIntercept = false;
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			/*
			 * mDetector.onTouchEvent(event);转移到此处，让mDetector也收到ACTION_DOWN的事件，主要用于解决，
			 * 拖动时，图片跳转的问题。因为onInterceptTouchEvent会给ACTION_DOWN
			 * 消耗掉。
			 */
			mDetector.onTouchEvent(event);
			mFirstX = event.getX();
			mFirstY = event.getY();
			break;
		case MotionEvent.ACTION_MOVE:
			float dx =Math.abs(event.getX() - mFirstX);
			float dy =Math.abs(event.getY() - mFirstY);
			if(dx > dy && dx >10){
				doIntercept = true;
			}else{
				doIntercept = false;
			}
			break;
		case MotionEvent.ACTION_UP:
			
			break;
		}
		return doIntercept;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);
		
		mDetector.onTouchEvent(event);
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mFirstX = event.getX();
			break;
		case MotionEvent.ACTION_MOVE:
			
			break;
		case MotionEvent.ACTION_UP:
			if(!mIsFling){
				int nextId = 0;
				float upX =event.getX();
				//fling to the right, scroll to the previous view
				if ((upX - mFirstX>getWidth()/2) && mCurrId>0) {// 手指向右滑动，超过屏幕的1/2  当前的mCurrId - 1
					nextId = mCurrId -1;
				//fling to the left, scroll to the next view
				}else if((mFirstX - upX)>getWidth()/2 && mCurrId <(getChildCount() -1)){// 手指向左滑动，超过屏幕的1/2  当前的mCurrId + 1
					nextId = mCurrId +1;
				}else{
					nextId = mCurrId;
				}
				scrollToView(nextId);
			}
			//reset fling flag to false;
			mIsFling = false;
			break;			
		default:
			break;
		}
		return true;
	}
	
	/**
	 * The method invalidate(), will lead computeScroll() been called.
	 */
	@Override
	public void computeScroll() {
		System.out.println("-------computeScroll()");
		if(mScroller.computeScrollOffset()){
			int newX = mScroller.getCurrX();
			scrollTo(newX, 0);
			invalidate();
		}
	}
	
	public void scrollToView(int nextId){
		mCurrId = nextId>=0?nextId:0;
		mCurrId = nextId<=(getChildCount()-1)?nextId:(getChildCount()-1);
		//瞬间移动
//		scrollTo(mCurrId*getWidth() , 0);
		int dx = mCurrId*getWidth() - getScrollX(); // finalX - currX = dx
		
		if(mOnPageChangedListener!=null){
			mOnPageChangedListener.onPageChanged(mCurrId);
		}
		mScroller.startScroll(getScrollX(), 0, dx, 0 , 500);
		//This is very important,otherwise the unfling state the view won't scroll
		invalidate();
	}
	
	public interface OnPageChangedListener{
		public void onPageChanged(int currId);
	}
}
